//
// Created by HP on 2022/1/21.
//

#include "lve_game_object.h"

namespace lve {

    // Matrix corresponds to translate * Ry * Rx * Rz * scale transformation
    // Rotation convention uses tait-bryan angles with axis order Y(1), X(2), Z(3)
    // glm::mat4 mat4() {
    //     // 1. 平移
    //     // 创建 4x4 平移矩阵
    //     // 1 0 0 dx
    //     // 0 1 0 dy
    //     // 0 0 1 dz
    //     // 0 0 0 1
    //     auto transform = glm::translate(glm::mat4{1.f}, transition);
    //     // 2. 旋转
    //     // 3D 旋转: 通过欧拉角描述 (还可以通过四元数来描述, 四元数有点超纲)
    //     // 欧拉角旋转矩阵有 12 种类型, 每种都是等价的, 现在使用 Y1_Z2_X3 型
    //     transform = glm::rotate(transform, rotation.y, {0.f, 1.f, 0.f}); // 绕 Y 旋转
    //     transform = glm::rotate(transform, rotation.x, {1.f, 0.f, 0.f}); // 绕 X 旋转
    //     transform = glm::rotate(transform, rotation.z, {0.f, 0.f, 1.f}); // 绕 Z 旋转
    //     // 3. 缩放
    //     // glm::scale(transform_mat4, scale_vec3) => Transition_mat4 * Scale_mat4
    //     //               sx 0  0  0
    //     // Scale_mat4 => 0  sy 0  0
    //     //               0  0  sz 0
    //     //               0  0  0  1
    //     transform = glm::scale(transform, scale);
    //     return transform;
    // }

    // https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
    glm::mat4 TransformComponent::mat4() {
        const float c3 = glm::cos(rotation.z);
        const float s3 = glm::sin(rotation.z);
        const float c2 = glm::cos(rotation.x);
        const float s2 = glm::sin(rotation.x);
        const float c1 = glm::cos(rotation.y);
        const float s1 = glm::sin(rotation.y);
        return glm::mat4{
            {
                scale.x * (c1 * c3 + s1 * s2 * s3),
                scale.x * (c2 * s3),
                scale.x * (c1 * s2 * s3 - c3 * s1),
                0.0f,
                },
                {
                scale.y * (c3 * s1 * s2 - c1 * s3),
                scale.y * (c2 * c3),
                scale.y * (c1 * c3 * s2 + s1 * s3),
                0.0f,
                },
                {
                scale.z * (c2 * s1),
                scale.z * (-s2),
                scale.z * (c1 * c2),
                0.0f,
                },
                {translation.x, translation.y, translation.z, 1.0f}};
    }

    glm::mat3 TransformComponent::normalMatrix() {
        const float c3 = glm::cos(rotation.z);
        const float s3 = glm::sin(rotation.z);
        const float c2 = glm::cos(rotation.x);
        const float s2 = glm::sin(rotation.x);
        const float c1 = glm::cos(rotation.y);
        const float s1 = glm::sin(rotation.y);
        const glm::vec3 invScale = 1.0f / scale;

        return glm::mat3 {
            {
                invScale.x * (c1 * c3 + s1 * s2 * s3),
                invScale.x * (c2 * s3),
                invScale.x * (c1 * s2 * s3 - c3 * s1),
            },
            {
                invScale.y * (c3 * s1 * s2 - c1 * s3),
                invScale.y * (c2 * c3),
                invScale.y * (c1 * c3 * s2 + s1 * s3),
            },
            {
                invScale.z * (c2 * s1),
                invScale.z * (-s2),
                invScale.z * (c1 * c2),
            },
        };
    }
}